#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 动态内存经典例题

// 对NULL解引用，内存泄漏
void GetMemory(char *p)
{
    // 把p修改为二级指针，修改test中str的值
    // 或者设置返回值，修改str的值
    p = (char *)malloc(100);
}
void test()
{
    char *str = NULL;
    GetMemory(str);
    strcpy(str, "hello world");
    printf(str);
    free(str);
    str = NULL;
}

// 野指针
char *GetMemory2()
{
    char p[] = "hello world";
    return p;
}
void test2()
{
    char *str = NULL;
    str = GetMemory2();
    printf(str);
}
int main()
{

    return 0;
}

// 对野指针进行操作，非法访问内存
void test3()
{
    char *str = (char *)malloc(100);
    strcpy(str, "hello");
    free(str);
    if (str != NULL)
    {
        strcpy(str, "world");
    }
}

/*1. 未初始化指针
在你的代码中，int *ptr; 声明了一个指针变量 ptr，但是没有给它分配一个有效的内存地址。指针 ptr 是一个局部变量，它存储的值是一个不确定的地址（即一个“野指针”），所以当你尝试执行 *ptr = 10; 时，实际上是试图访问一个未知的内存位置，这会导致未定义行为。

2. 非法访问内存
因为 ptr 没有指向一个有效的内存位置，你试图通过 *ptr = 10; 将值 10 存储到一个无效的地址，这可能会导致程序崩溃或其他意外行为。

*/
// int *f2()
// {
//     int *ptr;
//     *ptr = 10;
//     return ptr;
// }

// 柔性数组,结构中的最后一个元素允许是未知大小的数组
// 结构体中的柔性数组成员前必须至少一个其他成员
// sizeof返回的这种结构大小不包括柔性数组的内存
// 包含柔性数组成员的结果用malloc函数进行动态分配
// 分配的内存应该大于结构体的大小，以适应柔性数组的预期大小
struct S
{
    char c;
    int i;
    int arr[0];
};

// 柔性数组的优势
// 方便内存释放
// 有利于访问速度，减少内存碎片
int main()
{
    struct S *ps = (struct *)malloc(sizeof(struct S) + 20);
    if (ps == NULL)
    {
        perror("malloc fail");
        return;
    }
    ps->c = 'w';
    ps->i = 666;
    for (int i = 0; i < 5; i++)
    {
        ps->arr[i] = i;
    }
    for (i = 0; i < 5; i++)
    {
        printf("%d ", ps->arr[i]);
    }
    // 空间不够了
    struct S *tmp = realloc(ps, sizeof(struct S) + 40);
    if (tmp != NULL)
    {
        ps = tmp;
    }
    else
    {
        perror("realloc fail");
    }
    free(ps);
    ps = NULL;
    return 0;
}

// 程序运行起来时，程序中的数据都是放在内存中
// 如果要保存这些数据，不至于丢失，我们可以使用文件来保存信息，文件放在硬盘上
// c语言操作文件